/*
 * Copyright (c) 2020 Carnegie Lee
 * All rights reserved
 */
package com.geekc.zkdistributelock.lock.impl;

import com.geekc.zkdistributelock.constant.DistributeLockConst;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.CuratorEventType;
import org.apache.zookeeper.CreateMode;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 优化的分布式锁方案 - 基于zk临时顺序节点
 * @author Carnegie Lee
 */
public class OptimizeDistributeLock extends AbstractDistributeLock {

    private final CuratorFramework curatorFramework;

    private static volatile CountDownLatch countDownLatch;

    private final String basePath;

    private final String path;

    public OptimizeDistributeLock(CuratorFramework curatorFramework, String lockName) {
        super();
        this.curatorFramework = curatorFramework;
        this.countDownLatch = new CountDownLatch(1);
        this.basePath = DistributeLockConst.DISTRIBUTE_LOCK_ROOT_PATH + "/" + lockName;
        this.path = DistributeLockConst.DISTRIBUTE_LOCK_ROOT_PATH + "/" + lockName + "/" + lockName;
    }

    @Override
    protected boolean tryLock() {
        boolean isLocked = false;
        try {
            String s = curatorFramework.create()
                    .creatingParentsIfNeeded()
                    .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                    .forPath(path);

            List<String> list = curatorFramework.getChildren().forPath(basePath);
            Collections.sort(list);
            s = s.substring(basePath.length() + 1);
            if (s.equals(list.get(0))) {
                isLocked = true;
            } else {
                isLocked = false;
                CountDownLatch countDownLatch = new CountDownLatch(1);
                int index = list.indexOf(s) - 1;
                final String lastNode = list.get(index);
                curatorFramework.getChildren()
                        .watched()
                        .inBackground((client, event) -> {
                            if (event.getType().equals(CuratorEventType.CHILDREN)) {
                                countDownLatch.countDown();
                            }
                        })
                        .forPath(basePath + "/" + lastNode);
                countDownLatch.await();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return isLocked;
    }

    @Override
    protected boolean tryRelease() {
        boolean isRelease;
        try {
            if (null != curatorFramework.checkExists().forPath(path)) {
                curatorFramework.delete()
                        .deletingChildrenIfNeeded()
                        .forPath(path);
            }
            isRelease = true;
        } catch (Exception e) {
            isRelease = false;
        }
        return isRelease;
    }
}
